Allow "cycles" through dev-deps
authorAlex Crichton <alex@alexcrichton.com>
Wed, 24 Sep 2014 05:10:32 +0000 (22:10 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Fri, 3 Oct 2014 01:38:15 +0000 (18:38 -0700)
Development dependencies can never be the root of a cycle because nothing
depends on a development dependency, so there's no need to track the start of a
cycle at the edge going out to a development dependency.

If a cycle is later detected, it will still be reported.

src/cargo/core/resolver.rs
tests/test_cargo_compile.rs

index d33bfe618b60fb0ec851cbdfd1ca4759ce245599..d2af447b6e7828782d5c33da5fb03f7310330663 100644 (file)
@@ -315,12 +315,6 @@ fn resolve_deps<'a, R: Registry>(parent: &Summary,
                                  method: ResolveMethod,
                                  ctx: &mut Context<'a, R>)
                                  -> CargoResult<()> {
-    // Dependency graphs are required to be a DAG
-    if !ctx.visited.insert(parent.get_package_id().clone()) {
-        return Err(human(format!("Cyclic package dependency: package `{}` \
-                                  depends on itself", parent.get_package_id())))
-    }
-
     let dev_deps = match method {
         ResolveEverything => true,
         ResolveRequired(dev_deps, _, _) => dev_deps,
@@ -402,13 +396,25 @@ fn resolve_deps<'a, R: Registry>(parent: &Summary,
             ctx.seen.insert((name, source_id), version.clone());
             ctx.resolve.graph.add(summary.get_package_id().clone(), []);
         }
+
+        // Dependency graphs are required to be a DAG. Non-transitive
+        // dependencies (dev-deps), however, can never introduce a cycle, so we
+        // skip them.
+        if dep.is_transitive() &&
+           !ctx.visited.insert(summary.get_package_id().clone()) {
+            return Err(human(format!("Cyclic package dependency: package `{}` \
+                                      depends on itself",
+                                     summary.get_package_id())))
+        }
         try!(resolve_deps(summary,
                           ResolveRequired(false, dep.get_features(),
                                           dep.uses_default_features()),
                           ctx));
+        if dep.is_transitive() {
+            ctx.visited.remove(summary.get_package_id());
+        }
     }
 
-    ctx.visited.remove(parent.get_package_id());
     Ok(())
 }
 
index 7a9ed2a0376d3f8d3da552d127afe02c36018f85..764e7524cd8963b04c8e67498522fd403030fafc 100644 (file)
@@ -1082,8 +1082,8 @@ test!(self_dependency {
         "#)
         .file("src/test.rs", "fn main() {}");
     assert_that(p.cargo_process("build"),
-                execs().with_status(101).with_stderr("\
-Cyclic package dependency: package `test v0.0.0 ([..])` depends on itself
+                execs().with_status(0).with_stdout("\
+[..] test v0.0.0 ([..])
 "));
 })